# coding=utf-8
import reversion
from django.db import models
from datetime import datetime
from django.db.models import Q
from stdimage import StdImageField
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import AbstractBaseUser, Permission
from core.managers import NaturalPersonManager, GroupManager, UserManager, CompanyManager
from core.validators import validate_only_white_spaces, validate_cpf, validate_past_date, validate_cnpj, validate_future_date, CPF_REGEX, CNPJ_REGEX, PHONE_REGEX, PHONE_MESSAGE, CPF_MESSAGE, CNPJ_MESSAGE, POSTAL_CODE_REGEX, POSTAL_CODE_MESSAGE


class MainMenu(models.Model):
    name = models.CharField(max_length=50, verbose_name=_('Name'))
    description = models.TextField(blank=True, null=True, verbose_name=_('Description'))

    def __unicode__(self):
        return self.name

    def getUserMenus(self, permissions):
        menus = []
        for menu in self.menu_set.all():
            if menu.hasPermission(permissions):
                menus.append(menu)
        return menus

    class Meta:
        verbose_name = _('Topic')
        verbose_name_plural = _('Topics')


class Menu(models.Model):
    name = models.CharField(max_length=50, verbose_name=_('Name'))
    description = models.TextField(blank=True, null=True, verbose_name=_('Description'))
    mainMenu = models.ForeignKey(MainMenu, verbose_name=_('Section'))

    def __unicode__(self):
        return self.name

    def hasPermission(self, permissions):
        for permission in permissions:
            for action in self.action_set.all():
                p_name = action.permission.content_type.app_label + "." + action.permission.codename
                if p_name == permission:
                    return True
        return False

    class Meta:
        verbose_name = _('Menu')
        verbose_name_plural = _('Menus')


class Action(models.Model):
    menu = models.ForeignKey(Menu, verbose_name=_('Menu'))
    permission = models.OneToOneField(Permission, verbose_name=_('Permission'))

    def __unicode__(self):
        return self.permission.name

    class Meta:
        verbose_name = _('Action')
        verbose_name_plural = _('Actions')


class Package(models.Model):
    name = models.CharField(max_length=100, validators=[validate_only_white_spaces], verbose_name=_('Name'))
    description = models.TextField(validators=[validate_only_white_spaces], verbose_name=_('Description'))
    creation_date = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_('Creation Date'))
    price = models.DecimalField(max_digits=10, decimal_places=2, help_text='99,99', verbose_name=_('Price'), )
    active = models.BooleanField(default=True, verbose_name=_('Active'))
    permissions = models.ManyToManyField(Permission, verbose_name=_('Permissions'))

    class Meta:
        verbose_name = _('Package')
        verbose_name_plural = _('Packages')

    def __unicode__(self):
        return self.name


class Contract(models.Model):
    attachment = models.FileField(upload_to='uploads/contratos', verbose_name=_('Attachment'))
    signed_date = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_('Signature Date'))
    package = models.ForeignKey(Package, verbose_name=_('Package'))
    expiration = models.DateField(validators=[validate_future_date], verbose_name=_('Expiration'))
    active = models.BooleanField(default=True, verbose_name=_('Active'))
    observation = models.TextField(null=True, blank=True, validators=[validate_only_white_spaces], verbose_name=_('Observation'))

    class Meta:
        verbose_name = _('Contract')
        verbose_name_plural = _('Contract')

    def __unicode__(self):
        return str(self.id)


class State(models.Model):
    name = models.CharField(max_length=150, unique=True, validators=[validate_only_white_spaces], verbose_name=_('Name'))
    acronym = models.CharField(max_length=2, unique=True, validators=[validate_only_white_spaces], verbose_name=_('Acronym'))

    class Meta:
        verbose_name = _('State')
        verbose_name_plural = _('States')

    def __unicode__(self):
        return self.name


class City(models.Model):
    name = models.CharField(max_length=150, validators=[validate_only_white_spaces], verbose_name=_('Name'))
    state = models.ForeignKey(State, verbose_name=_('State'))

    class Meta:
        verbose_name = _('City')
        verbose_name_plural = _('Cities')

    def __unicode__(self):
        return "%s - %s" % (self.name, self.state.acronym)

    def clean(self):
        if self.name and self.state:
            existent_city = City.objects.filter(Q(name__exact=self.name) & Q(state__exact=self.state) & ~Q(id=self.id))
            if existent_city:
                raise ValidationError(_('There is a city with this name'))


class Address(models.Model):
    street = models.CharField(max_length=200, validators=[validate_only_white_spaces], verbose_name=_('Street'))
    neighbor = models.CharField(max_length=200, validators=[validate_only_white_spaces], verbose_name=_('Neighborhood'))
    postal_code = models.CharField(max_length=9, validators=[RegexValidator(
        regex=POSTAL_CODE_REGEX, message=POSTAL_CODE_MESSAGE)]
        , verbose_name=_('Postal Code'))
    number = models.CharField(max_length=5, null=True, blank=True, verbose_name=_('Number'))
    complement = models.CharField(max_length=200, null=True, blank=True, verbose_name=_('Complement'))
    city = models.ForeignKey(City, verbose_name=_('City'))

    class Meta:
        verbose_name = _('Address')
        verbose_name_plural = _('Addresses')

    def __unicode__(self):
        return "%s, %s - %s, %s" % (self.street, self.neighbor, self.city.name, self.city.state.acronym)


class Contact(models.Model):
    residential_phone = models.CharField(max_length=14, null=True, blank=True, validators=[validate_only_white_spaces, RegexValidator(
        regex=PHONE_REGEX, message=PHONE_MESSAGE)], verbose_name=_('Residential Phone'))
    cell_phone = models.CharField(max_length=14, null=True, blank=True, validators=[validate_only_white_spaces], verbose_name=_('Cell Phone'))
    work_phone = models.CharField(max_length=14, null=True, blank=True, validators=[validate_only_white_spaces], verbose_name=_('Work Phone'))

    class Meta:
        verbose_name = _('Contact')
        verbose_name_plural = _('Contacts')

    def __unicode__(self):
        return self.cell_phone

    def clean(self):
        if not self.residential_phone and not self.cell_phone and not self.work_phone:
            raise ValidationError(_('It\'s required informe at least one phone for contact'))


class Group(models.Model):
    name = models.CharField(max_length=80, validators=[validate_only_white_spaces], verbose_name=_('Name'))
    contract = models.ForeignKey(Contract, verbose_name=_('Contract'))
    permissions = models.ManyToManyField(Permission, related_name='groups', verbose_name=_('Permissions'))

    objects = GroupManager()

    class Meta:
        verbose_name = _('Group')
        verbose_name_plural = _('Groups')

    def __unicode__(self):
        return self.name

    def clean(self):
        if self.contract and self.name:
            existent_group = Group.objects.filter(Q(name__exact=self.name) & Q(contract__exact=self.contract) & ~Q(id=self.id))
            if existent_group:
                raise ValidationError(_('There is another group with this name'))


class User(AbstractBaseUser):
    email = models.EmailField(unique=True, validators=[validate_only_white_spaces], verbose_name=_('Email'))
    contract = models.ForeignKey(Contract, null=True, blank=True, verbose_name=_('Contract'))
    # superusers( Anderson, Nataliel e Lori ) não possuem contrato

    is_staff = models.BooleanField(default=False, verbose_name=_('Staff'))

    is_active = models.BooleanField(default=True, verbose_name=_('Active'))

    date_joined = models.DateTimeField(default=datetime.now, verbose_name=_('Creation Date'))

    is_superuser = models.BooleanField(default=False, verbose_name=_('Administrator'))
    groups = models.ManyToManyField(Group, blank=True, verbose_name=_('Groups'))
    user_permissions = models.ManyToManyField(Permission, blank=True, verbose_name=_('Permissions'))

    USERNAME_FIELD = 'email'

    objects = UserManager()

    class Meta:
        verbose_name = _('User')
        verbose_name_plural = _('Users')

    def get_full_name(self):
        return self.email

    def get_short_name(self):
        return self.email

    def get_group_permissions_ids(self, user=None):
        if self.is_anonymous():
            return set()

        permissions = set()
        if self.is_superuser:
            for p in Permission.objects.all():
                permissions.add(p.id)
        else:
            for group in self.groups.all():
                for p in group.permissions:
                    permissions.add(p.id)

        return permissions

    def get_group_permissions(self, user=None):
        if self.is_anonymous():
            return set()

        permissions = set()
        if self.is_superuser:
            permissions = Permission.objects.all()
        else:
            for group in self.groups.all():
                for p in group.permissions:
                    permissions.update(p)
        permissions = permissions.values_list('content_type__app_label', 'codename').order_by()

        return set(["%s.%s" % (ct, name) for ct, name in permissions])

    def get_all_permissions(self, user=None):
        if self.is_anonymous():
            return set()
        permissions = set(["%s.%s" % (p.content_type.app_label, p.codename) for p in self.user_permissions.select_related()])
        permissions.update(self.get_group_permissions(user))
        return permissions

    def get_all_permissions_ids(self, user=None):
        if self.is_anonymous():
            return set()
        permissions = set()
        for p in self.user_permissions.select_related():
            permissions.add(p.id)
        permissions.update(self.get_group_permissions_ids(user))
        return permissions

    def has_perm(self, perm, obj=None):

        if self.is_active and self.is_superuser:
            return True

        if not self.is_active:
            return False

        return perm in self.get_all_permissions(obj)

    def has_perms(self, perm_list, obj=None):
        for perm in perm_list:
            if not self.has_perm(perm, obj):
                return False
        return True

    def has_module_perms(self, app_label):
        # Active superusers have all permissions.
        if self.is_active and self.is_superuser:
            return True

        return bool(len([p for p in self.get_all_permissions(self) if p[:p.index('.')] == app_label]))

    def get_username(self):
        return self.email


class Person(models.Model):
    user = models.OneToOneField(User, verbose_name=_('User'))
    name = models.CharField(max_length=200, validators=[validate_only_white_spaces], verbose_name=_('Name'))
    creation_date = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_('Creation Date'))
    address = models.OneToOneField(Address, verbose_name=_('Address'))
    contact = models.OneToOneField(Contact, verbose_name=_('Contact'))
    photo = StdImageField(upload_to='uploads/person', blank=True, null=True, verbose_name=_('Photo'))

    class Meta:
        verbose_name = _('Person')
        verbose_name_plural = _('People')

    def delete(self, *args, **kwargs):
        if self.user:
            self.user.delete()
        if self.address:
            self.address.delete()
        if self.contact:
            self.contact.delete()

        super(Person, self).delete(*args, **kwargs)

    def __unicode__(self):
        return self.name


class Company(Person):

    objects = CompanyManager()

    cnpj = models.CharField(max_length=18, unique=True, validators=[RegexValidator(
        regex=CNPJ_REGEX, message=CNPJ_MESSAGE), validate_cnpj], verbose_name=_('CNPJ'))
    social_reason = models.CharField(max_length=150, validators=[validate_only_white_spaces], verbose_name=_('Social Reason'))

    class Meta:
        verbose_name = _('Gym')
        verbose_name_plural = _('Gyms')


class NaturalPerson(Person):

    objects = NaturalPersonManager()

    CIVIL_STATE_CHOICES = (('0', _('Single')), ('1', _('Married')), ('2', _('Widower')), ('3', _('Divorced')))
    BLOOD_GROUP_CHOICES = (('0', 'A'), ('1', 'B'), ('2', 'AB'), ('3', 'O'))
    RH_FACTOR_CHOICES = (('0', _('Positive')), ('1', _('Negative')))
    SEX_CHOICES = (('0', _('Male')), ('1', _('Female')))

    cpf = models.CharField(max_length=14, help_text="EX: 000.000.000.00", unique=True, validators=[RegexValidator(
        regex=CPF_REGEX, message=CPF_MESSAGE), validate_cpf], verbose_name=_('CPF'))
    birth_date = models.DateField(validators=[validate_past_date], verbose_name=_('Date of Birth'))
    civil_state = models.CharField(max_length=2, choices=CIVIL_STATE_CHOICES, verbose_name=_('Civil State'))
    blood_group = models.CharField(max_length=2, choices=BLOOD_GROUP_CHOICES, verbose_name=_('Blood Group'))
    rh_factor = models.CharField(max_length=2, choices=RH_FACTOR_CHOICES, verbose_name=_('RH Factor'))
    sex = models.CharField(max_length=2, choices=SEX_CHOICES, verbose_name=_('Sex'))
    gym = models.ForeignKey(Company, blank=True, null=True, verbose_name=_('Gym'))

    class Meta:
        verbose_name = _('Natural Person')
        verbose_name_plural = _('Natural People')


reversion.register(Action)
reversion.register(MainMenu)
reversion.register(Menu)
reversion.register(Permission)
reversion.register(Package)
reversion.register(Contract)
reversion.register(State)
reversion.register(City)
reversion.register(Address)
reversion.register(Contact)
reversion.register(Group)
reversion.register(User)
reversion.register(NaturalPerson)
reversion.register(Company)
